package cn.jbolt.core.gen;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.jbolt.core.annotation.TableBind;
import cn.jbolt.core.base.JBoltIDGenMode;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.base.config.JBoltProjectConfig;
import cn.jbolt.core.consts.JBoltConst;
import cn.jbolt.core.db.sql.Sql;
import cn.jbolt.core.model.Permission;
import cn.jbolt.core.util.JBoltConsoleUtil;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.template.Engine;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Controller Service html生成器
 */
public abstract class JBoltMainLogicGenerator {
    public final String SEPARATOR = File.separator;
    /**
     * JBolt项目绝对路径 修改这个就行
     */
    private final String PROJECT_PATH = System.getProperty("user.dir");
    /**
     * ProjectSystemLogTargetType.java的绝对路径
     */
    private final String ProjectSystemLogTargetType_PATH = PROJECT_PATH + SEPARATOR + "src" + SEPARATOR + "main" + SEPARATOR + "java" + SEPARATOR + "cn" + SEPARATOR + "jbolt" + SEPARATOR + "extend" + SEPARATOR + "systemlog" + SEPARATOR + "ProjectSystemLogTargetType.java";

    /**
     * 执行生成任务
     */
    public void generate() {
        JBoltConsoleUtil.printMessageWithDate("开始执行生成 ...");
        genLogicBeans.forEach(genLogicBean -> generateOne(genLogicBean));
        JBoltConsoleUtil.printMessageWithDate("全部生成 结束 ...");
        JBoltConsoleUtil.printMessageWithDate("==请刷新项目目录，检查生成结果==");
    }

    /**
     * 构造函数
     */
    public JBoltMainLogicGenerator() {
        JBoltConsoleUtil.printMessage("-------------------------JFinal Main Logic Generator-------------------------");
        initGenConfig();
        initEngine();
    }

    /**
     * 初始化生成配置
     */
    protected abstract void initGenConfig();

    /**
     * 初始化生成模板引擎
     */
    private void initEngine() {
        JBoltConsoleUtil.printMessageWithDate("初始化模板引擎 ...");
        engine = new Engine();
//		engine.setStaticFieldExpression(true);
//		engine.setStaticMethodExpression(true);
        engine.setToClassPathSourceFactory(); // 从 class path 内读模板文件
        engine.addSharedMethod(new StrKit());
        engine.addSharedFunction(controllerCommonTemplate);
        engine.addSharedFunction(serviceCommonTemplate);
        engine.addEnum(IndexHtmlLayoutType.class);
    }

    /**
     * 检查是否存在一行里包含指定代码
     *
     * @param codeLines
     * @param code
     * @return
     */
    private boolean checkFileContainCode(List<String> codeLines, String code) {
        String tmpCode;
        for (String codeLine : codeLines) {
            tmpCode = codeLine.trim();
            if (StrKit.isBlank(tmpCode)
                    ||
                    tmpCode.startsWith("package ")
                    ||
                    tmpCode.startsWith("public class ")
                    ||
                    tmpCode.startsWith("return ")
                    ||
                    tmpCode.equals("}")
            ) {
                continue;
            }
            if (codeLine.indexOf(code) != -1) {
                return true;
            }
        }
        return false;
    }

    /**
     * 生成systemLogTargetType
     *
     * @param systemLogTargetType
     */
    private void genProjectSystemLogTargetType(SystemLogTargetType systemLogTargetType) {
        JBoltConsoleUtil.printMessageWithDate("正在生成ProjectSystemLogTargetType...");
        boolean exists = FileUtil.exist(ProjectSystemLogTargetType_PATH);
        if (!exists) {
            throw new RuntimeException(ProjectSystemLogTargetType_PATH + "文件不存在");
        }

        List<String> codeLines = FileUtil.readLines(ProjectSystemLogTargetType_PATH, CharsetUtil.UTF_8);
        if (codeLines == null || codeLines.size() == 0) {
            throw new RuntimeException(ProjectSystemLogTargetType_PATH + "文件内容异常");
        }
        String code = systemLogTargetType.getName() + "(\"" + systemLogTargetType.getText() + "\"," + systemLogTargetType.getValue() + ")";
        //如果已经存在 就略过
        if (checkFileContainCode(codeLines, code)) {
            JBoltConsoleUtil.printMessage(String.format("ProjectSystemLogTargetType 文件已经存在[%s][%s]定义，略过！", systemLogTargetType.getName(), systemLogTargetType.getValue()));
            return;
        }
        int size = codeLines.size();
        String tmpCode;
        int insertIndex = 0;
        int startIndex = -1;
        for (int i = 1; i < size; i++) {
            tmpCode = codeLines.get(i);
            if (StrKit.isBlank(tmpCode)) {
                continue;
            }
            if (startIndex == -1 && tmpCode.trim().startsWith("public enum ProjectSystemLogTargetType")) {
                startIndex = i + 1;
            }
            if (tmpCode.trim().equals(";")) {
                insertIndex = i;
            }
        }
        boolean needProcessUpComma = true;
        if (insertIndex == 0) {
            insertIndex = startIndex;
            code = code + ",";
            needProcessUpComma = false;
        }

        if (startIndex > 0) {
            codeLines.add(insertIndex, "\t" + code);
            if (needProcessUpComma) {
                String tmp;
                String tmpTrim;
                for (int i = insertIndex - 1; i > startIndex; i--) {
                    tmp = codeLines.get(i);
                    if (StrKit.isBlank(tmp)) {
                        continue;
                    }
                    tmpTrim = tmp.trim();
                    if (tmpTrim.endsWith(",") || tmpTrim.endsWith(";") || tmpTrim.endsWith("{") || tmpTrim.endsWith("}")) {
                        break;
                    }
                    if (tmpTrim.charAt(tmpTrim.length() - 1) != ',') {
                        codeLines.set(i, "\t" + tmpTrim + ",");
                        break;
                    }
                }

            }
            JBoltConsoleUtil.printMessageWithDate("正在重新生成新的ProjectSystemLogTargetType...");
            //执行重新生成
            FileUtil.writeLines(codeLines, ProjectSystemLogTargetType_PATH, CharsetUtil.UTF_8);
        }
    }

    /**
     * 生成Permisison 和 PermissionKey
     *
     * @param permissions
     * @param checkPermissionKeys
     * @param isSystemAdminUncheck
     */
    private void genPermissionAndKeys(List<Permission> permissions, String checkPermissionKeys, boolean isSystemAdminUncheck) {
        if (permissions == null || permissions.size() == 0) {
            return;
        }
        JBoltConsoleUtil.printMessageWithDate("正在生成数据库 权限资源...");
        DruidPlugin druid = JBoltProjectConfig.createDruidPlugin();
        ActiveRecordPlugin arp = new ActiveRecordPlugin(druid);
        // 设置方言
        JBoltConfig.setDialect(arp);
        // 设置不区分大小写
        arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));
        arp.setShowSql(true);
        arp.addMapping("jb_permission", Permission.class);
//		arp.addMapping("jb_user",User.class);
        druid.start();
        arp.start();
        List<Permission> saveList = new ArrayList<>();
        Permission permission;
        Long dbPermissionId;
        Sql maxSortRankSql = Sql.me(JBoltConfig.MAIN_DB_TYPE).max("sort_rank").from("jb_permission").eq("pid", 0);
        Long maxSortRank = Db.queryLong(maxSortRankSql.toSql());
        int newRank = maxSortRank == null ? 1 : (maxSortRank.intValue() + 1);

        try {
            for (int i = 0; i < permissions.size(); i++) {
                permission = permissions.get(i);
                if (permission.getId() != null) {
                    throw new RuntimeException("不可设置Permission的id字段值");
                }
                if (StrKit.isBlank(permission.getName())) {
                    throw new RuntimeException("必须设置Permission的name字段值");
                }
                if (StrKit.isBlank(permission.getPermissionKey())) {
                    throw new RuntimeException("必须设置Permission的permission_key字段值");
                }
                dbPermissionId = Db.queryFirst("select id from jb_permission where permission_key = ?", permission.getPermissionKey());
                if (dbPermissionId != null && dbPermissionId.longValue() > 0) {
                    continue;
                }
                if (permission.getPermissionLevel() == null || permission.getPermissionLevel() <= 0) {
                    permission.setPermissionLevel(1);
                }
                if (permission.getIsMenu() == null) {
                    permission.setIsMenu(true);
                }
                if (permission.getIsSystemAdminDefault() == null) {
                    permission.setIsSystemAdminDefault(isSystemAdminUncheck);
                }
                if (permission.getOpenType() == null || permission.getOpenType() <= 0) {
                    permission.setOpenType(Permission.OPEN_TYPE_DEFAULT);
                }
                if (permission.getPid() == null) {
                    permission.setPid(0L);
                }
                permission.setIsTargetBlank(false);
                permission.setSortRank(newRank);
                permission.autoProcessIdValue();
                saveList.add(permission);
                newRank++;
            }


            boolean success = Db.tx(() -> {
                if (saveList.size() > 0) {
                    Db.batchSave(saveList, saveList.size());
                }
                return true;
            });
            if (success && saveList.size() > 0) {
                JBoltInnerPermissionKeyGen.genToCurrentProject();
            }
        } finally {
            arp.stop();
            druid.stop();
        }


    }


    /**
     * 针对一个Modelclass进行生成
     *
     * @param mainLogicBean
     */
    public void generateOne(JBoltMainLogicBean mainLogicBean) {
        JBoltConsoleUtil.printMessageWithDate(String.format("正在生成:%s...", mainLogicBean.getMainModelClass().getName()));
        // 生成依赖的权限Permission和PermissionKey
        genPermissionAndKeys(mainLogicBean.getPermissions(), mainLogicBean.getCheckPermissionKeys(), mainLogicBean.isUnCheckIfSystemAdmin());
        // 生成依赖的ProjectSystemNoticeTargetType
        genProjectSystemLogTargetType(mainLogicBean.getSystemLogTargetType());
        // 生成Controller
        genController(mainLogicBean);
        // 生成Service
        genService(mainLogicBean);
        // 生成index.html
        genIndexHtml(mainLogicBean);
        // 也有crud的话 才生成form add edit的html
        if (mainLogicBean.isCrudType()) {
            // 生成add.html
            genAddHtml(mainLogicBean);
            // 生成edit.html
            genEditHtml(mainLogicBean);
            // 生成_form.html
            genFormHtml(mainLogicBean);
        }
    }

    /**
     * 生成Index.htlm
     *
     * @param mainLogicBean
     */
    private void genIndexHtml(JBoltMainLogicBean mainLogicBean) {
        // model名
        String modelName = mainLogicBean.getMainModelClass().getSimpleName();
        JBoltConsoleUtil.printMessageWithDate("正在生成index.html...");
        // view相对路径
        String viewFolder = mainLogicBean.getViewFolder();
        // view物理路径
        String targetOutputDir = getDirFromViewForlder(viewFolder);
        JBoltConsoleUtil.printMessageWithDate(String.format("index.html生成路径:%s...", targetOutputDir));
        // 如果存在 忽略
        if (FileUtil.exist(targetOutputDir + File.separator + "index.html")) {
            JBoltConsoleUtil.printMessageWithDate("index.html文件[%s]已存在,忽略生成！");
            return;
        }
        // 模板数据
        Kv datas = Kv.by("modelName", modelName).set("mainLogicBean", mainLogicBean);
        // 处理针对一个ModelClass在Controller层要生成的方法
        processIndexHtmlJboltField(mainLogicBean.getMainModelClass(), mainLogicBean.getPrimaryKeyAttr(), datas);
        // 执行渲染模板得到代码文本
        String content = engine.getTemplate(indexHtmlTemplate).renderToString(datas);
        // 执行文件生成
        writeToFile(targetOutputDir, "index.html", content);

    }

    /**
     * 生成_form.html
     *
     * @param mainLogicBean
     */
    private void genFormHtml(JBoltMainLogicBean mainLogicBean) {
        // model名
        String modelName = mainLogicBean.getMainModelClass().getSimpleName();
        JBoltConsoleUtil.printMessageWithDate("正在生成_form.html...");
        String viewFolder = mainLogicBean.getViewFolder();
        String targetOutputDir = getDirFromViewForlder(viewFolder);
        JBoltConsoleUtil.printMessageWithDate(String.format("_form.html生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + "_form.html")) {
            JBoltConsoleUtil.printMessageWithDate("_form.html文件[%s]已存在,忽略生成！");
            return;
        }
        // 模板数据
        Kv datas = Kv.by("modelName", modelName).set("mainLogicBean", mainLogicBean);
        // 处理针对一个ModelClass在Form里的字段元素
        processFormHtmlJboltField(mainLogicBean.getMainModelClass(), mainLogicBean.getPrimaryKeyAttr(), datas);

        // 执行渲染模板得到代码文本
        String content = engine.getTemplate(formHtmlTemplate).renderToString(datas);
        // 执行文件生成
        writeToFile(targetOutputDir, "_form.html", content);

    }

    /**
     * 生成Edit.html
     *
     * @param mainLogicBean
     */
    private void genEditHtml(JBoltMainLogicBean mainLogicBean) {
        JBoltConsoleUtil.printMessageWithDate("正在生成edit.html...");
        String viewFolder = mainLogicBean.getViewFolder();
        String targetOutputDir = getDirFromViewForlder(viewFolder);
        JBoltConsoleUtil.printMessageWithDate(String.format("edit.html生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + "edit.html")) {
            JBoltConsoleUtil.printMessageWithDate("edit.html文件[%s]已存在,忽略生成！");
            return;
        }
        // 执行渲染模板得到代码文本
        String content = engine.getTemplate(editHtmlTemplate)
                .renderToString(Kv.by("action", mainLogicBean.getRealControllerKey() + "/update"));
        // 执行文件生成
        writeToFile(targetOutputDir, "edit.html", content);

    }

    /**
     * 生成add.html
     *
     * @param mainLogicBean
     */
    private void genAddHtml(JBoltMainLogicBean mainLogicBean) {
        JBoltConsoleUtil.printMessageWithDate("正在生成add.html...");
        String viewFolder = mainLogicBean.getViewFolder();
        String targetOutputDir = getDirFromViewForlder(viewFolder);
        JBoltConsoleUtil.printMessageWithDate(String.format("add.html生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + "add.html")) {
            JBoltConsoleUtil.printMessageWithDate("add.html文件[%s]已存在,忽略生成！");
            return;
        }
        // 执行渲染模板得到代码文本
        String content = engine.getTemplate(addHtmlTemplate)
                .renderToString(Kv.by("action", mainLogicBean.getRealControllerKey() + "/save"));
        // 执行文件生成
        writeToFile(targetOutputDir, "add.html", content);
    }

    /**
     * 通用controller模板
     *
     * @param mainLogicBean
     * @return
     */
    private List<String> getCommonControllerMethods(JBoltMainLogicBean mainLogicBean) {
        List<String> genMehtods = new ArrayList<String>();
        genMehtods.add("index");
        if (mainLogicBean.isCrudType()) {
            genMehtods.add("add");
            genMehtods.add("edit");
            genMehtods.add("save");
            genMehtods.add("update");
            if (mainLogicBean.isNeedToolbar() && mainLogicBean.isCrudType()) {
                genMehtods.add("deleteByIds");
            }
            if (mainLogicBean.isNeedTrDeleteBtn()) {
                genMehtods.add("delete");
            }
        }
        return genMehtods;
    }

    private List<JBoltGenMethod> getCommonServiceMethods(JBoltMainLogicBean mainLogicBean) {
        List<JBoltGenMethod> genMehtods = new ArrayList<JBoltGenMethod>();
        if (mainLogicBean.isNeedPaginate()) {
            genMehtods.add(new JBoltGenMethod("paginateAdminDatas"));
        } else {
            genMehtods.add(new JBoltGenMethod("getAdminDatas"));
        }
        boolean hasAfterDelete = false;
        if (mainLogicBean.isCrudType()) {
            genMehtods.add(new JBoltGenMethod("save"));
            genMehtods.add(new JBoltGenMethod("update"));
            if (mainLogicBean.isNeedToolbar() && mainLogicBean.isCrudType()) {
                genMehtods.add(new JBoltGenMethod("deleteByIds"));
                hasAfterDelete = true;
            }
            if (mainLogicBean.isNeedTrDeleteBtn()) {
                genMehtods.add(new JBoltGenMethod("delete"));
                hasAfterDelete = true;
            }
        }
        if (hasAfterDelete) {
            genMehtods.add(new JBoltGenMethod("afterDelete"));
        }
        if (mainLogicBean.isCheckDelete()) {
            genMehtods.add(new JBoltGenMethod("checkCanDelete"));
        }
        genMehtods.add(new JBoltGenMethod("systemLogTargetType"));
        return genMehtods;
    }

    /**
     * 生成Service
     *
     * @param mainLogicBean
     */
    private void genService(JBoltMainLogicBean mainLogicBean) {
        Class<? extends Model> modelClass = mainLogicBean.getMainModelClass();
        // model名
        String modelName = modelClass.getSimpleName();
        // service名
        String serviceName = modelName + "Service";
        // service全名
        String serviceFullName = serviceName + ".java";
        // 目标package
        String targetPackageName = mainLogicBean.getJavaPackage();
        JBoltConsoleUtil.printMessageWithDate(String.format("正在生成Service:%s...", serviceFullName));
        // 生成到指定目录
        String targetOutputDir = getDirFromPackage(targetPackageName);
        JBoltConsoleUtil.printMessageWithDate(String.format("Service生成路径:%s...", targetOutputDir));
        // 如果已经存在就忽略
        if (FileUtil.exist(targetOutputDir + File.separator + serviceFullName)) {
            JBoltConsoleUtil.printMessageWithDate(String.format("Service文件[%s]已存在,忽略生成！", serviceFullName));
            return;
        }
        // 模板数据
        Kv data = Kv.by("author", mainLogicBean.getAuthor()).set("targetPackageName", targetPackageName)
                .set("modelName", modelName).set("serviceName", serviceName)
                .set("modelImport", modelClass.getPackage().getName() + "." + modelName);
        // 所需生成的方法名
        List<JBoltGenMethod> genMehtods = processServiceGenMethods(mainLogicBean);
        data.set("methods", genMehtods);
        data.set("mainLogicBean", mainLogicBean);
        data.set("paramIdType", getServiceParamIdTypeByGenMode(modelClass));
        String primaryKey = mainLogicBean.getPrimaryKey();
        if (primaryKey.contains(",")) {
            data.set("getIdMethodName", "getId");
        } else {
            data.set("getIdMethodName", "get" + StrUtil.upperFirst(StrUtil.toCamelCase(primaryKey.toLowerCase())));
        }
        // 执行渲染模板得到代码文本
        String content = engine.getTemplate(serviceTemplate).renderToString(data);
        // 执行文件生成
        writeToFile(targetOutputDir, serviceFullName, content);
    }

    /**
     * 生成Controller
     *
     * @param mainLogicBean
     */
    private void genController(JBoltMainLogicBean mainLogicBean) {
        // model名字
        String modelName = mainLogicBean.getMainModelClass().getSimpleName();
        // Controller名字
        String controllerName = modelName + "AdminController";
        // Controller全名
        String controllerFullName = controllerName + ".java";
        // 目标package
        String targetPackageName = mainLogicBean.getJavaPackage();
        JBoltConsoleUtil.printMessageWithDate(String.format("正在生成Controller:%s...", controllerFullName));
        // 输出目录
        String targetOutputDir = getDirFromPackage(targetPackageName);
        JBoltConsoleUtil.printMessageWithDate(String.format("Controller生成路径:%s...", targetOutputDir));
        // 如果文件已经存在 忽略生成
        if (FileUtil.exist(targetOutputDir + File.separator + controllerFullName)) {
            JBoltConsoleUtil.printMessageWithDate(String.format("Controller文件[%s]已存在,忽略生成！", controllerFullName));
            return;
        }
        // service名字
        String serviceName = modelName + "Service";
        // 准备模板数据
        Kv data = Kv.by("author", mainLogicBean.getAuthor()).set("targetPackageName", targetPackageName)
                .set("modelName", modelName).set("controllerName", controllerName).set("serviceName", serviceName)
                .set("modelImport", mainLogicBean.getMainModelClass().getPackage().getName() + "." + modelName);
        // 处理所需生成的方法名
        List<String> genMehtods = processContrllerGenMethods(mainLogicBean);
        data.set("methods", genMehtods);
        data.set("needPaginate", mainLogicBean.getNeedPaginate());
        data.set("unCheckIfSystemAdmin", mainLogicBean.isUnCheckIfSystemAdmin());
        data.set("getIdType", getGetIdTypeByGenMode(mainLogicBean.getMainModelClass()));
        data.set("controllerRemark", mainLogicBean.getPageTitle());
        data.set("pathValue", mainLogicBean.getControllerKey());
        data.set("pathViewPath", mainLogicBean.getViewFolder());
        data.set("usePathAnnotation", mainLogicBean.isUsePathAnnotation());
        data.set("checkPermissionKeys", mainLogicBean.getCheckPermissionKeys());
        data.set("isCRUD", mainLogicBean.getIsCRUD());
        data.set("isMainDataSource", mainLogicBean.getIsMainDataSource());
        // 执行渲染模板得到代码文本
        String content = engine.getTemplate(controllerTemplate).renderToString(data);
        // 执行文件生成 写到文件中
        writeToFile(targetOutputDir, controllerFullName, content);
    }

    /**
     * 根据ID策略获取IDType
     *
     * @param clazz
     * @return
     */
    private String getGetIdTypeByGenMode(Class<?> clazz) {
        TableBind tableBind = clazz.getAnnotation(TableBind.class);
        String idGenMode = tableBind.idGenMode();
        String idType = "Int";
        switch (idGenMode) {
            case JBoltIDGenMode.AUTO_LONG:
                idType = "Long";
                break;
            case JBoltIDGenMode.AUTO_STRING:
                idType = "Str";
                break;
            case JBoltIDGenMode.BIGSERIAL:
                idType = "Int";
                break;
            case JBoltIDGenMode.SERIAL:
                idType = "Int";
                break;
            case JBoltIDGenMode.UUID:
                idType = "";
                break;
            case JBoltIDGenMode.SEQUENCE:
                idType = "Int";
                break;
            case JBoltIDGenMode.SEQUENCE_LONG:
                idType = "Long";
                break;
            case JBoltIDGenMode.SNOWFLAKE:
                idType = "Long";
                break;
            case JBoltIDGenMode.SNOWFLAKE_STRING:
                idType = "Str";
                break;
            case JBoltIDGenMode.ASSIGN_STRING:
                idType = "Str";
                break;
            case JBoltIDGenMode.ASSIGN_INT:
                idType = "Int";
                break;
            case JBoltIDGenMode.ASSIGN_LONG:
                idType = "Long";
                break;
            default:
                idType = "Int";
                break;
        }
        return idType;
    }

    /**
     * 根据ID策略获取serivce里方法参数中的IDType
     *
     * @param modelClass
     * @return
     */
    private String getServiceParamIdTypeByGenMode(Class<?> modelClass) {
        TableBind tableBind = modelClass.getAnnotation(TableBind.class);
        String idGenMode = tableBind.idGenMode();
        String idType = "Integer";
        switch (idGenMode) {
            case JBoltIDGenMode.AUTO:
                idType = "Integer";
                break;
            case JBoltIDGenMode.AUTO_LONG:
                idType = "Long";
                break;
            case JBoltIDGenMode.AUTO_STRING:
                idType = "String";
                break;
            case JBoltIDGenMode.BIGSERIAL:
                idType = "Integer";
                break;
            case JBoltIDGenMode.SERIAL:
                idType = "Integer";
                break;
            case JBoltIDGenMode.UUID:
                idType = "String";
                break;
            case JBoltIDGenMode.SEQUENCE:
                idType = "Integer";
                break;
            case JBoltIDGenMode.SEQUENCE_LONG:
                idType = "Long";
                break;
            case JBoltIDGenMode.SNOWFLAKE:
                idType = "Long";
                break;
            case JBoltIDGenMode.SNOWFLAKE_STRING:
                idType = "String";
                break;
            case JBoltIDGenMode.ASSIGN_STRING:
                idType = "String";
                break;
            case JBoltIDGenMode.ASSIGN_INT:
                idType = "Integer";
                break;
            case JBoltIDGenMode.ASSIGN_LONG:
                idType = "Long";
                break;
            default:
                idType = "Integer";
                break;
        }
        return idType;
    }

    /**
     * 得到package物理路径
     *
     * @param targetPackageName
     * @return
     */
    private String getDirFromPackage(String targetPackageName) {
        return projectPath + "/src/main/java/" + targetPackageName.replace(".", "/");
    }

    /**
     * 得到view物理路径
     *
     * @param viewFolder
     * @return
     */
    private String getDirFromViewForlder(String viewFolder) {
        if (viewFolder.charAt(0) != JBoltConst.SLASH) {
            viewFolder = JBoltConst.SLASH_STR + viewFolder;
        }
        return projectPath + "/src/main/webapp" + viewFolder;
    }

    private Filter<Method> commonGetMethodFilter = new Filter<Method>() {

        @Override
        public boolean accept(Method method) {
            String name = method.getName();
            boolean isBoolean = method.getReturnType() == Boolean.class;
            boolean isSortRank = method.getReturnType() == Integer.class
                    && method.getName().equalsIgnoreCase("getsortrank");
            boolean isPid = method.getName().equalsIgnoreCase("getpid")
                    || method.getName().equalsIgnoreCase("getparentid");
            return name.startsWith("get") && !name.equalsIgnoreCase("getboolean")
                    && (isBoolean || isSortRank || isPid);
        }
    };

    /**
     * 处理针对一个ModelClass在Service层要生成的方法
     *
     * @param mainLogicBean
     * @return
     */
    private List<JBoltGenMethod> processServiceGenMethods(JBoltMainLogicBean mainLogicBean) {
        // 先得到通用的，然后判断有不需要的就删掉，有特殊的就新增
        List<JBoltGenMethod> genMehtods = getCommonServiceMethods(mainLogicBean);
        List<Method> getMethods = ClassUtil.getPublicMethods(mainLogicBean.getMainModelClass().getSuperclass(),
                commonGetMethodFilter);
        if (getMethods != null && getMethods.size() > 0) {
            boolean hasAfterToggle = false;
            for (Method method : getMethods) {
                // 返回值是boolean的 生成toogleXXX
                boolean isBoolean = method.getReturnType() == Boolean.class;
                if (isBoolean && mainLogicBean.isCrudType()) {
                    genMehtods.add(new JBoltGenMethod(method.getName().replace("get", "toggle"),
                            method.getAnnotation(JBoltField.class)));
                    hasAfterToggle = true;
                    continue;
                }
                // getSortRank有的话 需要生成对应的上下 move 和初始化
                boolean isSortRank = method.getReturnType() == Integer.class
                        && method.getName().equalsIgnoreCase("getsortrank");
                if (isSortRank && mainLogicBean.isCrudType()) {
                    genMehtods.add(new JBoltGenMethod("up"));
                    genMehtods.add(new JBoltGenMethod("down"));
                    genMehtods.add(new JBoltGenMethod("move"));
                    genMehtods.add(new JBoltGenMethod("initRank"));
                    mainLogicBean.setNeedSort(true);
                    continue;
                }
                // 如果有pid字段的getPid 说明表结构是父子tree关系结构
                boolean isPid = method.getName().equalsIgnoreCase("getpid")
                        || method.getName().equalsIgnoreCase("getparentid");
                if (isPid) {
                    genMehtods.add(new JBoltGenMethod("tree"));
                    mainLogicBean.setHasPid(true);
                    continue;
                }

            }

            if (hasAfterToggle) {
                genMehtods.add(new JBoltGenMethod("checkCanToggle"));
                genMehtods.add(new JBoltGenMethod("afterToggle"));
            }
            if (mainLogicBean.isCheckDelete() || hasAfterToggle) {
                genMehtods.add(new JBoltGenMethod("checkInUse"));
            }
        }
        return genMehtods;
    }

    private Filter<Method> commonIndexHtmlGetMethodFilter = new Filter<Method>() {

        @Override
        public boolean accept(Method method) {
            String name = method.getName();
            boolean isPid = method.getName().equalsIgnoreCase("getpid")
                    || method.getName().equalsIgnoreCase("getparentid");
            boolean isId = method.getName().equalsIgnoreCase("getid");
            boolean isPassword = method.getReturnType() == String.class && (method.getName()
                    .equalsIgnoreCase("getpassword")
                    || (method.getName().startsWith("get") && method.getName().toLowerCase().endsWith("password")));
            return name.startsWith("get") && !isId && !isPassword && !isPid
                    && !name.equalsIgnoreCase("getboolean");
        }
    };

    private Filter<Method> commonFormHtmlGetMethodFilter = new Filter<Method>() {

        @Override
        public boolean accept(Method method) {
            String name = method.getName();
            boolean isPid = method.getName().equalsIgnoreCase("getpid")
                    || method.getName().equalsIgnoreCase("getparentid");
            boolean isId = method.getName().equalsIgnoreCase("getid");
            boolean isUserId = (method.getName().equalsIgnoreCase("getuserid")
                    || method.getName().equalsIgnoreCase("getcreateuserid")
                    || method.getName().equalsIgnoreCase("getupdateuserid"));
            boolean isCreateUpdateTime = method.getName().equalsIgnoreCase("getcreatetime")
                    || method.getName().equalsIgnoreCase("getupdatetime");
            boolean isPassword = method.getReturnType() == String.class && (method.getName()
                    .equalsIgnoreCase("getpassword")
                    || (method.getName().startsWith("get") && method.getName().toLowerCase().endsWith("password")));
            return name.startsWith("get") && !isUserId && !isId && !isPassword && !isPid && !isCreateUpdateTime
                    && !name.equalsIgnoreCase("getboolean");
        }
    };

    /**
     * 处理针对一个ModelClass在Controller层要生成的方法
     *
     * @param clazz
     * @param primaryKeyAttr
     * @param datas
     * @return
     */

    private List<JBoltFieldBean> processIndexHtmlJboltField(Class<?> clazz, String primaryKeyAttr, Kv datas) {
        List<JBoltFieldBean> jboltFieldBeans = new ArrayList<JBoltFieldBean>();
        List<Method> getMethods = ClassUtil.getPublicMethods(clazz.getSuperclass(), commonIndexHtmlGetMethodFilter);
        boolean needSort = false;
        if (getMethods != null && getMethods.size() > 0) {
            JBoltField field;
            String columnName;
            for (Method method : getMethods) {
                field = method.getAnnotation(JBoltField.class);
                if (field == null) {
                    continue;
                }
                columnName = field.name().toLowerCase();
                if (columnName.equals("sortrank")) {
                    needSort = true;
                    continue;
                }
                if (columnName.equals("pwd_salt")) {
                    continue;
                }
                if (columnName.contains("_pwd")) {
                    continue;
                }
                if (columnName.equals("password")) {
                    continue;
                }
                if (columnName.equalsIgnoreCase(primaryKeyAttr)) {
                    continue;
                }
                jboltFieldBeans.add(new JBoltFieldBean(field));
            }
            // 按照order
            jboltFieldBeans = CollUtil.sortByProperty(jboltFieldBeans, "order");
        }
        datas.set("needSort", needSort);
        datas.set("ths", jboltFieldBeans);
        return jboltFieldBeans;
    }

    /**
     * 处理针对一个ModelClass在Form里的字段元素
     *
     * @param clazz
     * @param primaryKeyAttr
     * @param datas
     * @return
     */
    private List<JBoltFieldBean> processFormHtmlJboltField(Class<?> clazz, String primaryKeyAttr, Kv datas) {
        List<JBoltFieldBean> jboltFieldBeans = new ArrayList<JBoltFieldBean>();
        List<Method> getMethods = ClassUtil.getPublicMethods(clazz.getSuperclass(), commonFormHtmlGetMethodFilter);
        if (getMethods != null && getMethods.size() > 0) {
            JBoltField field;
            String columnName;
            JBoltFieldBean bean;
            for (Method method : getMethods) {
                field = method.getAnnotation(JBoltField.class);
                if (field == null) {
                    continue;
                }
                columnName = field.columnName().toLowerCase();
                bean = new JBoltFieldBean(field);
                if (columnName.equals("sortrank")) {
                    continue;
                }
                if (columnName.equals("enable")) {
                    continue;
                }
                if (columnName.equals("pwd_salt")) {
                    continue;
                }
                if (columnName.equalsIgnoreCase(primaryKeyAttr)) {
                    continue;
                }
                if (bean.getType().equalsIgnoreCase("boolean")) {
                    bean.setUiType(JBoltFieldBean.TYPE_RADIO_BOOLEAN);
                } else if (bean.getType().equalsIgnoreCase("Integer")
                        || bean.getType().equalsIgnoreCase("BigDecimal")) {
                    if (bean.getType().equalsIgnoreCase("BigDecimal") && bean.getFixed() > 0) {
                        bean.setUiType(JBoltFieldBean.TYPE_INPUT_PNUMBER);
                    }
                    if (columnName.contains("year")) {
                        bean.setUiType(JBoltFieldBean.TYPE_YEAR);
                    } else if (columnName.equalsIgnoreCase("age") || columnName.contains("_age")) {
                        if (bean.getType().equalsIgnoreCase("Integer") && bean.getMaxLength() > 3) {
                            bean.setUiType(JBoltFieldBean.TYPE_INPUT_PINT);
                            bean.setMaxLength(3);
                            bean.setFixed(0);
                        }
                    } else if (columnName.endsWith("_category") || columnName.contains("category_id")) {
                        bean.setUiType(JBoltFieldBean.TYPE_SELECT);
                    } else if (columnName.endsWith("_type") || columnName.contains("type_id")) {
                        bean.setUiType(JBoltFieldBean.TYPE_SELECT);
                    } else if (columnName.contains("state") || columnName.contains("states")
                            || columnName.contains("status")) {
                        bean.setUiType(JBoltFieldBean.TYPE_SELECT);
                    } else if (columnName.endsWith("_id")) {
                        bean.setUiType(JBoltFieldBean.TYPE_AUTOCOMPLETE);
                    } else {
                        bean.setUiType(JBoltFieldBean.TYPE_INPUT_PNUMBER);
                    }
                } else if (bean.getType().equalsIgnoreCase("Date")) {
                    bean.setUiType(JBoltFieldBean.TYPE_DATE);
                } else if (bean.getType().equalsIgnoreCase("Time")) {
                    bean.setUiType(JBoltFieldBean.TYPE_TIME);
                } else {
                    if (columnName.endsWith("_pwd") || columnName.endsWith("password")
                            || columnName.contains("password")) {
                        bean.setUiType(JBoltFieldBean.TYPE_INPUT_PASSWORD);
                    } else if (columnName.endsWith("_ids")) {
                        bean.setUiType(JBoltFieldBean.TYPE_CHECKBOX);
                    } else if (columnName.endsWith("_type") || columnName.contains("type_id")) {
                        bean.setUiType(JBoltFieldBean.TYPE_SELECT);
                    } else if (columnName.endsWith("_category") || columnName.contains("category_id")) {
                        bean.setUiType(JBoltFieldBean.TYPE_SELECT);
                    } else if (columnName.contains("state") || columnName.contains("states")
                            || columnName.contains("status")) {
                        bean.setUiType(JBoltFieldBean.TYPE_SELECT);
                    } else if (columnName.endsWith("_id")) {
                        bean.setUiType(JBoltFieldBean.TYPE_AUTOCOMPLETE);
                    } else if (columnName.contains("week")) {
                        bean.setUiType(JBoltFieldBean.TYPE_WEEK);
                    } else if (columnName.contains("month")) {
                        bean.setUiType(JBoltFieldBean.TYPE_MONTH);
                    } else if (columnName.contains("year")) {
                        bean.setUiType(JBoltFieldBean.TYPE_YEAR);
                    }
                }
                jboltFieldBeans.add(bean);
            }
            // 按照order
            jboltFieldBeans = CollUtil.sortByProperty(jboltFieldBeans, "order");
        }
        datas.set("cols", jboltFieldBeans);
        return jboltFieldBeans;
    }

    /**
     * 处理针对一个ModelClass在Controller层要生成的方法
     *
     * @param mainLogicBean
     * @return
     */
    private List<String> processContrllerGenMethods(JBoltMainLogicBean mainLogicBean) {
        // 先得到通用的，然后判断有不需要的就删掉，有特殊的就新增
        List<String> genMehtods = getCommonControllerMethods(mainLogicBean);
        // 得到model所有public getter method
        List<Method> getMethods = ClassUtil.getPublicMethods(mainLogicBean.getMainModelClass().getSuperclass(),
                commonGetMethodFilter);
        if (getMethods != null && getMethods.size() > 0) {
            // 每个getter 循环处理
            for (Method method : getMethods) {
                // boolean类型特殊处理 需要提供toggleXXX方法
                boolean isBoolean = method.getReturnType() == Boolean.class;
                if (isBoolean && mainLogicBean.isCrudType()) {
                    genMehtods.add(method.getName().replace("get", "toggle"));
                    continue;
                }
                // 如果是存在sort_rank字段的getSortRank方法 那就需要加排序了
                boolean isSortRank = method.getReturnType() == Integer.class
                        && method.getName().equalsIgnoreCase("getsortrank");
                if (isSortRank && mainLogicBean.isCrudType()) {
                    // 排序三兄弟 上下和初始化 后面还得加动态move
                    genMehtods.add("up");
                    genMehtods.add("down");
                    genMehtods.add("move");
                    genMehtods.add("initRank");
                    continue;
                }
                // 如果有pid字段的getPid 说明表结构是父子tree关系结构
                boolean isPid = method.getReturnType() == Integer.class && method.getName().equalsIgnoreCase("getpid");
                if (isPid) {
                    genMehtods.add("tree");
                    continue;
                }
            }
        }
        return genMehtods;
    }

    /**
     * 写入文件 如果存在 不进行任何操作 不覆盖
     *
     * @param targetOutputDir
     * @param fileName
     * @param content
     * @throws IOException
     */
    private void writeToFile(String targetOutputDir, String fileName, String content) {
        if (!FileUtil.exist(targetOutputDir)) {
            FileUtil.mkdir(targetOutputDir);
        }

        String target = targetOutputDir + File.separator + fileName;
        if (!FileUtil.exist(target)) {
            FileUtil.writeUtf8String(content, target);
        }

    }

    /**
     * 添加到生成队列中
     *
     * @param mainLogicBean
     */
    public void addGenBean(JBoltMainLogicBean mainLogicBean) {
        genLogicBeans.add(mainLogicBean);
    }

    /**
     * 项目路径
     */
    protected static final String projectPath = System.getProperty("user.dir");
    private static final String controllerTemplate = "/gentpl/controller_template.jf";
    private static final String controllerCommonTemplate = "/gentpl/controller_common_template.jf";
    private static final String serviceCommonTemplate = "/gentpl/service_common_template.jf";
    private static final String serviceTemplate = "/gentpl/service_template.jf";
    private static final String indexHtmlTemplate = "/gentpl/index_html_template.jf";
    private static final String addHtmlTemplate = "/gentpl/add_html_template.jf";
    private static final String editHtmlTemplate = "/gentpl/edit_html_template.jf";
    private static final String formHtmlTemplate = "/gentpl/form_html_template.jf";
    // 生成的配置队列
    private final List<JBoltMainLogicBean> genLogicBeans = new ArrayList<JBoltMainLogicBean>();
    // 模板引擎实例
    private Engine engine;

}
